#include <cassert>

#include "SmallObjectAllocator2.h"



namespace MemMgr
{

SmallObjectAllocator2::SmallObjectAllocator2(size_t iPageSize, size_t iMaxObjectSize) :
	mPoolId(iMaxObjectSize/NUM_BIT_ALIGNMENT, MAX_ID_NUM),
	mPool(),
	mPageSize(iPageSize),
	mMaxObjectSize(iMaxObjectSize)
{
	assert((0 != iPageSize) && ((iPageSize & (iPageSize - 1)) == 0) && "Must be a power of two!");
	assert((0 != iMaxObjectSize) && ((iMaxObjectSize & (iMaxObjectSize - 1)) == 0) && "Must be a power of two!");
	assert(iMaxObjectSize/NUM_BIT_ALIGNMENT <= MAX_ID_NUM);
}



void* SmallObjectAllocator2::Allocate(size_t iNumBytes)
{
	if(iNumBytes > mMaxObjectSize)
	{
		return operator new(iNumBytes);
	}
	
	AtomSizeU poolIdIndex = RetrieveId(iNumBytes);

	if(mPoolId[poolIdIndex] == MAX_ID_NUM)
	{
		const size_t poolSize = mPool.size();
		mPool.resize(poolSize +1);
		FixedSizeAllocator2& newFixedAllocator = mPool.back();
		newFixedAllocator.Initialize(iNumBytes, mPageSize);
		mPoolId[poolIdIndex] = poolSize;
		return newFixedAllocator.Allocate();
	}

	assert(mPool[mPoolId[poolIdIndex]].GetBlockSize() >= iNumBytes);

	return mPool[mPoolId[poolIdIndex]].Allocate();
}



void SmallObjectAllocator2::Deallocate(void* iPtr, std::size_t iNumBytes)
{
	assert(iNumBytes > mMaxObjectSize);

	AtomSizeU poolIdIndex = RetrieveId(iNumBytes);

	assert(mPool[mPoolId[poolIdIndex]].GetBlockSize() >= iNumBytes);
	assert(mPoolId[poolIdIndex] != MAX_ID_NUM);

	mPool[mPoolId[poolIdIndex]].Deallocate(iPtr);
}

}